﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace SortingAlgorithms
{
    public partial class frmSort : Form
    {
        public enum SortTypes
        {
            BubbleSort,
            BucketSort,
            CocktailSort,
            CountingSort,
            GnomeSort,
            InsertionSort,
            RadixSort,
            SelectionSort,
            ShellSort
        }
        public enum SortTypesNotAvailableYet
        {
            BeadSort,
            BinaryTreeSort,
            InPlaceMergeSort,
            MergeSort,
            PigeonholeSort
        }
     
        private Int32 ItemSize = 4;
        private Int32[] columns;
        private Int32[] columnsOriginal;
        private List<Int16> movements;
        private Int32 ItemWidth = 0;
        private Int32 ItemHeight = 0;
        private Int32 CurrentIndex = 0;
        private Int32 CurrentValue = 0;
        private Int32 TotalEvents = 0;
        private Bitmap bm;
        private Graphics g;
        private SortTypes CurrentSortType;

        private delegate void ShowSortDelegate(Int32 currentIndex, Int32 currentValue);
        private delegate void StartedDelegate();
        private delegate void FinishedDelegate();

        public frmSort()
        {
            InitializeComponent();
            ddlSize.SelectedIndex = ItemSize;
            ddlAlgorithm.DataSource = new MikeKappel.Com.CS.Data.BindingLists.EnumBindingList(typeof(SortTypes));
        }
        private void frmSort_Load(object sender, EventArgs e)
        {

        }

        private void frmSort_CollectionChanging(object sender, EventArgs e)
        {

        }
        private void frmSort_CollectionChanged(object sender, EventArgs e)
        {

        }
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            Reset(true);
        }
        private void frmSort_Resize(object sender, EventArgs e)
        {
            Reset(true);
        }
        private void ddlSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            ItemSize = Int32.Parse(ddlSize.SelectedItem.ToString());
            Reset(true);
        }
        private void btnGo_Click(object sender, EventArgs e)
        {
            CurrentSortType = (SortTypes)Enum.Parse(typeof(SortTypes), ddlAlgorithm.SelectedItem.ToString().Replace(" ", ""));
            Thread imageThread = new Thread(new ParameterizedThreadStart(SortItems));
            imageThread.Start(CurrentSortType);
        }
        private void btnStop_Click(object sender, EventArgs e)
        {
            if (CurrentSortType == SortTypes.CountingSort
                || CurrentSortType == SortTypes.BucketSort)
                MessageBox.Show("Can not be stoped.");
            else
                Stopped();
        }
        private void btnReset_Click(object sender, EventArgs e)
        {
            Reset(false);
        }

        public Boolean ShowSortInvoke(Int32 currentIndex, Int32 currentValue)
        {
            if (!btnStop.Enabled)
                return false;
            Thread.Sleep(5);
            Invoke(new ShowSortDelegate(ShowSort), currentIndex, currentValue);
            return true;
        }
        public void ShowSort(Int32 currentIndex, Int32 currentValue)
        {
            TotalEvents += 1;

            movements[currentIndex]++;

            CurrentIndex = currentIndex;
            CurrentValue = currentValue;
            lblInfo.Text = "item[" + currentIndex + "]=" + currentValue + ";\nEvents:" + TotalEvents;

            //g.FillRectangle(new SolidBrush(Color.FromArgb(color, color, color)),
            //    new Rectangle(currentIndex * ItemSize, currentValue * ItemSize, ItemSize, ItemSize));
            //pbSort.Image = bm;

            bm = new Bitmap(pbSort.Width, pbSort.Height);
            g = Graphics.FromImage(bm);
            g.FillRectangle(new SolidBrush(Color.White), 0, 0, bm.Width, bm.Height);

            plot(Color.LightGray, columnsOriginal, pbSort, g, bm, ItemSize);
            plot(Color.Empty, columns, pbSort, g, bm, ItemSize);

            StringBuilder result = new StringBuilder();
            for ( Int32 i = 0; i < columns.Length; i++)
            {
                result.Append(columns[i] + ":" + columnsOriginal[i] + ":" + movements[i] + "\r\n");
            }
            txtSort.Text = result.ToString();

        }

        private void Reset(Boolean randomize)
        {
            Decimal dWidth = pbSort.Width / ItemSize;
            Decimal dHeight = pbSort.Height / ItemSize;
            lblInfo.Text = "Ready";

            //Reset Variables
            ItemWidth = (Int32)Math.Floor(dWidth);
            ItemHeight = (Int32)Math.Floor(dHeight);
            CurrentIndex = 0;
            CurrentValue = 0;
            TotalEvents = 0;

            if (randomize || columnsOriginal == null)
            {
                columnsOriginal = new Int32[ItemWidth];
                // load array with random values;
                Random random = new Random();
                for (Int32 i = 0; i < columnsOriginal.Length; i++)
                    columnsOriginal[i] = random.Next(0, ItemHeight);
            }

            columns = (Int32[])columnsOriginal.Clone();
            movements = new List<Int16>(ItemWidth);
            for (Int32 i = 0; i < columns.Length; i++)
                movements.Add(0);

            CreateImage();

            StringBuilder result = new StringBuilder();
            foreach (Int32 column in columns)
            {
                result.Append(column + "\r\n");
            }
            txtSort.Text = result.ToString();
            plot(Color.Empty, columns, pbSort, g, bm, ItemSize);
        }
        private void SortItems(Object boxedSortType)
        {
            SortTypes sortType = (SortTypes)boxedSortType;
            Invoke(new FinishedDelegate(Started));
            switch (sortType)
            {
                case SortTypes.BucketSort:
                    MikeKappel.Com.CS.SortingAlgorithms.BucketSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.BubbleSort:
                    MikeKappel.Com.CS.SortingAlgorithms.BubbleSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.CocktailSort:
                    MikeKappel.Com.CS.SortingAlgorithms.CocktailSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.CountingSort:
                    MikeKappel.Com.CS.SortingAlgorithms.CountingSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.GnomeSort:
                    MikeKappel.Com.CS.SortingAlgorithms.GnomeSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.InsertionSort:
                    MikeKappel.Com.CS.SortingAlgorithms.InsertionSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.SelectionSort:
                    MikeKappel.Com.CS.SortingAlgorithms.SelectionSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.RadixSort:
                    MikeKappel.Com.CS.SortingAlgorithms.RadixSort(columns, ShowSortInvoke);
                    break;
                case SortTypes.ShellSort:
                    MikeKappel.Com.CS.SortingAlgorithms.ShellSort(columns, ShowSortInvoke);
                    break;
                default:
                    MessageBox.Show(sortType.ToString() + " not expected");
                    break;
            }
            Invoke(new FinishedDelegate(Finished));
        }
        private void CreateImage()
        {
            bm = new Bitmap(pbSort.Width, pbSort.Height);
            g = Graphics.FromImage(bm);
            g.FillRectangle(new SolidBrush(Color.White), 0, 0, bm.Width, bm.Height);
        }
        private void Started()
        {
            btnStop.Enabled = true;
            btnReset.Enabled = false;
            btnGo.Enabled = false;
            btnGenerate.Enabled = false;
            ddlAlgorithm.Enabled = false;
            ddlSize.Enabled= false;
        }
        private void Stopped()
        {
            btnStop.Enabled = false;
            btnReset.Enabled = true;
            btnGo.Enabled = true;
            btnGenerate.Enabled = true;
            ddlAlgorithm.Enabled = true;
            ddlSize.Enabled = true;
        }
        private void Finished()
        {
            CreateImage();
            plot(Color.Gray, columnsOriginal, pbSort, g, bm, ItemSize);
            plot(Color.Empty, columns, pbSort, g, bm, ItemSize);
            lblInfo.Text = "Total Events:" + TotalEvents;
            Stopped();
        }
        private static void plot(Color colorIn, Int32[] items, PictureBox pictureBox, Graphics g, Bitmap bitmap, Int32 boxSize)
        {
            System.Drawing.Color color = colorIn;
            for (Int32 i = 0; i < items.Length; i++)
            {
                if (colorIn == Color.Empty)
                {
                    //Int32 colorInt = (Int32)Math.Floor(((Decimal)items[i] * 16581375m) / (Decimal)items.Length);
                    //color = System.Drawing.ColorTranslator.FromHtml("#" + colorInt.ToString("X"));
                    Int32 red = (Int32)Math.Floor(((Decimal)items[i] * 255m) / (Decimal)items.Length);
                    Int32 blue = (Int32)Math.Abs((Math.Floor(((Decimal)i * 255m) / (Decimal)items.Length))-255);
                    color = Color.FromArgb(red, 0, blue);
                }
                if (boxSize == 1)
                    bitmap.SetPixel(i * boxSize, items[i], color);
                else
                    g.FillRectangle(new SolidBrush(color), new Rectangle(i * boxSize, items[i] * boxSize, boxSize, boxSize));
            }
            pictureBox.Image = bitmap;
        }


    }
}
